#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
天翼TV客户端
按照现有标准实现，参考Go语言版本的189_tv实现
"""

import os
import time
import logging
import qrcode
import base64
import json
from typing import List, Optional, Dict, Any
from datetime import datetime
from io import BytesIO

from ...base.client import CloudStorageClient
from ...base.models import (
    LoginCredentials, PersistentLoginInfo, CloudFile, 
    AccountInfo, TrashItem
)
from ...base.exceptions import AuthException, FileNotFound, CloudStorageError, NetworkError
from .api import TianyiTVApi


class TianyiTVClient(CloudStorageClient):
    """天翼TV客户端 - 按照新标准实现"""
    
    def __init__(self):
        super().__init__()
        self._api = TianyiTVApi()
        self._logger = logging.getLogger(__name__)
        
        # 登录相关
        self._access_token = None
        self._refresh_token = None
        self._user_id = None
        self._username = None
        self._temp_uuid = None
        

    
    def _generate_qr_code(self, uuid: str) -> str:
        """生成二维码图片的base64数据"""
        try:
            # 生成二维码
            qr = qrcode.QRCode(version=1, box_size=10, border=5)
            qr.add_data(uuid)
            qr.make(fit=True)
            
            # 创建二维码图片
            img = qr.make_image(fill_color="black", back_color="white")
            
            # 转换为base64
            buffer = BytesIO()
            img.save(buffer, format='PNG')
            img_data = buffer.getvalue()
            buffer.close()
            
            # 生成HTML页面
            qr_base64 = base64.b64encode(img_data).decode('utf-8')
            qr_html = f"""
            <body>
                <h2>天翼TV登录二维码</h2>
                <img src="data:image/png;base64,{qr_base64}" alt="二维码"/>
                <br>
                <p>请使用手机扫描二维码登录</p>
                <p>或者点击链接: <a href="{uuid}">{uuid}</a></p>
            </body>
            """
            
            return qr_html
            
        except Exception as e:
            self._logger.error(f"生成二维码失败: {e}")
            return f"二维码生成失败: {e}"
    # 四阶段登录方法实现
    def trigger_login(self, credentials: LoginCredentials) -> str:
        """触发登录接口（第一阶段）
        
        Args:
            credentials: 登录凭据
            
        Returns:
            str: 登录会话标识符（二维码UUID）
            
        Raises:
            AuthException: 登录触发失败
        """
        try:
            self._username = credentials.username
            
            # 获取二维码UUID进行扫码登录
            self._logger.info("开始二维码登录流程...")
            uuid_result = self._api.get_qr_code_uuid()
            
            if not uuid_result or 'uuid' not in uuid_result:
                raise AuthException("获取二维码失败")
            
            self._temp_uuid = uuid_result['uuid']
            self._logger.info(f"获取到二维码UUID: {self._temp_uuid}")
            
            return self._temp_uuid
            
        except Exception as e:
            self._logger.error(f"触发登录失败: {e}")
            raise AuthException(f"触发登录失败: {str(e)}")
    
    def get_login_link(self, uuid: str) -> str:
        """获取登录链接
        
        Args:
            uuid: 二维码UUID
            
        Returns:
            str: 登录链接
        """
        return f"https://cloud.189.cn/api/portal/loginByQrCode.action?uuid={uuid}&requestSource=wap"
    
    def check_login_status(self, session_id: str) -> Optional[PersistentLoginInfo]:
        """检测登录状态接口（第二阶段）
        
        Args:
            session_id: 登录会话标识符（二维码UUID）
            
        Returns:
            Optional[PersistentLoginInfo]: 登录成功时返回持久化信息，否则返回None
            
        Raises:
            AuthException: 检查登录状态失败
        """
        try:
            # 检测二维码登录状态
            self._logger.info(f"检查二维码登录状态: {session_id}")
            login_result = self._api.check_qr_code_login_result(session_id)
            
            if login_result and 'accessToken' in login_result:
                self._access_token = login_result['accessToken']
                self._logger.info("二维码登录成功！")
                
                # 获取SessionKey和SessionSecret
                session_result = self._api.login_family_merge(self._access_token)
                
                if not session_result:
                    raise AuthException("获取会话信息失败")
                
                # 保存登录信息
                self._user_id = session_result.get('loginName', '')
                self._refresh_token = session_result.get('refreshToken', '')
                
                # 设置API的token信息
                self._api.token_info = session_result
                
                # 设置登录状态
                self._logged_in = True
                
                return self._create_persistent_info(session_result)
            else:
                # 二维码未扫描或登录失败
                self._logger.info("二维码尚未扫描或登录未完成")
            
            return None
            
        except Exception as e:
            self._logger.error(f"检查登录状态失败: {e}")
            raise AuthException(f"检查登录状态失败: {str(e)}")
    
    def serialize_login_info(self) -> str:
        """登录缓存信息序列化成字符串的接口（第三阶段）
        
        Returns:
            str: 序列化后的登录信息字符串
            
        Raises:
            AuthException: 序列化失败
        """
        try:
            if not self._logged_in:
                raise AuthException("未登录，无法序列化登录信息")
            
            # 构造登录信息字典
            login_info = {
                'access_token': self._access_token,
                'refresh_token': self._refresh_token,
                'user_id': self._user_id,
                'username': self._username,
                'logged_in': self._logged_in,
                'token_info': self._api.token_info,
                'timestamp': datetime.now().isoformat()
            }
            
            # 序列化为JSON字符串
            return json.dumps(login_info, ensure_ascii=False)
            
        except Exception as e:
            self._logger.error(f"序列化登录信息失败: {e}")
            raise AuthException(f"序列化登录信息失败: {str(e)}")
    
    def restore_login_from_string(self, serialized_info: str) -> bool:
        """登录接口恢复接口（第四阶段）
        
        Args:
            serialized_info: 序列化后的登录信息字符串
            
        Returns:
            bool: 恢复是否成功
            
        Raises:
            AuthException: 恢复登录失败
        """
        try:
            # 反序列化登录信息
            login_info = json.loads(serialized_info)
            
            # 恢复登录状态
            self._access_token = login_info.get('access_token')
            self._refresh_token = login_info.get('refresh_token')
            self._user_id = login_info.get('user_id')
            self._username = login_info.get('username')
            self._logged_in = login_info.get('logged_in', False)
            self._api.token_info = login_info.get('token_info')
            
            # 验证token是否有效
            if not self._validate_token():
                self._logged_in = False
                raise AuthException("Token已过期，请重新登录")
            
            self._logger.info("从序列化字符串成功恢复登录状态")
            return True
            
        except Exception as e:
            self._logger.error(f"从序列化字符串恢复登录状态失败: {e}")
            self._logged_in = False
            raise AuthException(f"恢复登录状态失败: {str(e)}")
    
    def get_account_info(self) -> AccountInfo:
        """
        获取账户信息
        
        Returns:
            AccountInfo: 账户信息
            
        Raises:
            AuthException: 未登录
            CloudStorageError: 获取失败
        """
        if not self.is_logged_in:
            raise AuthException("未登录")
        
        try:
            # 获取用户信息
            user_info = self._api.get_user_info(self._access_token)
            
            if not user_info:
                raise CloudStorageError("获取用户信息失败")
            
            # 获取容量信息
            capacity_info = self._api.get_capacity_info(self._access_token)
            
            total_space = 0
            used_space = 0
            
            if capacity_info:
                # 根据Go语言实现，处理容量信息
                if 'cloudCapacityInfo' in capacity_info:
                    total_space = capacity_info['cloudCapacityInfo'].get('totalSize', 0)
                    used_space = capacity_info['cloudCapacityInfo'].get('usedSize', 0)
                elif 'familyCapacityInfo' in capacity_info:
                    total_space = capacity_info['familyCapacityInfo'].get('totalSize', 0)
                    used_space = capacity_info['familyCapacityInfo'].get('usedSize', 0)
            
            return AccountInfo(
                user_id=user_info.get('loginName', ''),
                username=user_info.get('loginName', ''),
                email=user_info.get('loginName', ''),
                total_space=total_space,
                used_space=used_space
            )
            
        except Exception as e:
            self._logger.error(f"获取账户信息失败: {e}")
            raise CloudStorageError(f"获取账户信息失败: {str(e)}")
    
    def list_files(self, folder_id: Optional[str] = None) -> List[CloudFile]:
        """
        列出文件夹中的文件
        
        Args:
            folder_id: 文件夹ID，None表示根目录
            
        Returns:
            List[CloudFile]: 文件列表
            
        Raises:
            AuthException: 未登录
            FileNotFound: 文件夹不存在
            CloudStorageError: 获取失败
        """
        if not self.is_logged_in:
            raise AuthException("未登录")
        
        try:
            folder_id = folder_id or "-11"  # 根目录
            files_data = self._api.list_files_in_folder(folder_id, self._access_token, is_family=False)
            
            files = []
            for item in files_data:
                files.append(CloudFile(
                    file_id=item.get('id', ''),
                    name=item.get('name', ''),
                    path=item.get('path', ''),
                    size=item.get('size', 0),
                    is_folder=item.get('isFolder', False),
                    parent_id=item.get('parentId'),
                    created_at=self._parse_timestamp(item.get('createDate')),
                    modified_at=self._parse_timestamp(item.get('lastOpTime')),
                    md5=item.get('md5')
                ))
            
            return files
            
        except Exception as e:
            self._logger.error(f"列出文件失败: {e}")
            if "not found" in str(e).lower():
                raise FileNotFound(f"文件夹不存在: {folder_id}")
            raise CloudStorageError(f"列出文件失败: {str(e)}")
    
    def create_folder(self, name: str, parent_id: Optional[str] = None) -> CloudFile:
        """
        创建文件夹
        
        Args:
            name: 文件夹名称
            parent_id: 父文件夹ID，None表示根目录
            
        Returns:
            CloudFile: 创建的文件夹信息
            
        Raises:
            AuthException: 未登录
            FileNotFound: 父文件夹不存在
            CloudStorageError: 创建失败
        """
        if not self.is_logged_in:
            raise AuthException("未登录")
        
        try:
            parent_id = parent_id or "-11"  # 根目录
            folder_data = self._api.create_folder(name, parent_id, self._access_token, is_family=False)
            
            cloud_file = CloudFile(
                file_id=folder_data.get('id', ''),
                name=folder_data.get('name', name),
                path=folder_data.get('path', ''),
                size=0,
                is_folder=True,
                parent_id=parent_id,
                created_at=self._parse_timestamp(folder_data.get('createDate')),
                modified_at=self._parse_timestamp(folder_data.get('lastOpTime'))
            )
            
            self._logger.info(f"文件夹创建成功: {cloud_file.file_id}, 名称: {cloud_file.name}, 父文件夹: {parent_id}")
            return cloud_file
            
        except Exception as e:
            self._logger.error(f"创建文件夹失败: {e}")
            if "not found" in str(e).lower():
                raise FileNotFound(f"父文件夹不存在: {parent_id}")
            raise CloudStorageError(f"创建文件夹失败: {str(e)}")
    
    def upload_file(
        self, 
        file_name: str,
        file_data: bytes,
        parent_id: Optional[str] = None,
        overwrite: bool = False,
        progress_callback: Optional[callable] = None
    ) -> CloudFile:
        """
        上传文件
        
        Args:
            file_name: 文件名
            file_data: 文件数据
            parent_id: 父文件夹ID，None表示根目录
            overwrite: 是否覆盖同名文件
            progress_callback: 进度回调函数
            
        Returns:
            CloudFile: 上传后的文件信息
            
        Raises:
            CloudStorageError: 上传失败
        """
        try:
            if not file_data:
                raise CloudStorageError("文件数据为空")
            
            if not self._logged_in:
                raise AuthException("未登录，请先登录")
            
            # 计算文件MD5
            file_md5 = self._calculate_data_md5(file_data)
            if not file_md5:
                raise CloudStorageError("计算文件MD5失败")
            
            # 获取文件信息
            file_size = len(file_data)
            
            # 创建上传会话
            upload_info = self._api.create_upload_file(
                parent_id=parent_id or "-11",  # 根目录
                file_md5=file_md5,
                file_name=file_name,
                file_size=str(file_size),
                is_family=False  # 使用个人空间
            )
            
            # API直接返回字段，不在data中
            file_data_exists = upload_info.get('fileDataExists', 0)
            upload_url = upload_info.get('fileUploadUrl', '')
            commit_url = upload_info.get('fileCommitUrl', '')
            upload_file_id = upload_info.get('uploadFileId', 0)
            
            print(f"🔍 上传信息: {upload_info}")
            print(f"🔍 文件数据存在状态: {file_data_exists}")
            print(f"🔍 上传URL: {upload_url}")
            print(f"🔍 提交URL: {commit_url}")
            
            if file_data_exists == 1:
                # 文件已存在，直接提交
                self._logger.info("文件已存在于云端，直接提交")
            else:
                # 文件不存在，需要上传数据
                self._logger.info("文件不存在于云端，开始上传数据")
                
                if not upload_url:
                    raise CloudStorageError("上传URL为空，无法上传文件数据")
                
                # 上传文件数据
                self._api.upload_file_data(
                    upload_url=upload_url,
                    file_data=file_data,
                    upload_file_id=upload_file_id,
                    is_family=False
                )
            
            # 提交上传
            commit_result = self._api.commit_upload_file(
                commit_url=commit_url,
                upload_file_id=upload_file_id,
                is_family=False,  # 使用个人空间
                overwrite=True
            )
            
            # 解析返回的文件信息 - 支持JSON和XML格式
            file_data_result = None
            if 'file' in commit_result:
                # JSON格式
                file_data_result = commit_result['file']
            elif isinstance(commit_result, dict) and 'raw_response' in commit_result:
                # XML格式响应，需要解析
                raw_response = commit_result['raw_response']
                if raw_response.startswith('<?xml') or '<file>' in raw_response:
                    # 解析XML响应
                    try:
                        import xml.etree.ElementTree as ET
                        root = ET.fromstring(raw_response)
                        if root.tag == 'file':
                            file_data_result = {}
                            for child in root:
                                file_data_result[child.tag] = child.text
                    except Exception as xml_error:
                        self._logger.error(f"XML解析失败: {xml_error}")
                        raise CloudStorageError(f"提交上传响应解析失败: {xml_error}")
                else:
                    # 其他格式的原始响应
                    file_data_result = commit_result
            else:
                # 其他情况，直接使用响应
                file_data_result = commit_result
            
            if not file_data_result:
                raise CloudStorageError("无法解析提交上传的响应")
            
            # 创建并返回CloudFile对象
            return CloudFile(
                file_id=file_data_result.get('id', ''),
                name=file_data_result.get('name', file_name),
                path=f"/{file_name}",
                size=int(file_data_result.get('size', file_size)),
                is_folder=False,
                created_at=self._parse_timestamp(file_data_result.get('createDate')) if file_data_result.get('createDate') else None
            )
            
        except Exception as e:
            self._logger.error(f"上传文件失败: {e}")
            raise CloudStorageError(f"上传文件失败: {e}")
    
    def delete_file(self, file_id: str) -> None:
        """
        删除文件
        
        Args:
            file_id: 文件ID
            
        Raises:
            AuthException: 未登录
            FileNotFound: 文件不存在
            CloudStorageError: 删除失败
        """
        if not self.is_logged_in:
            raise AuthException("未登录")
        
        try:
            self._api.delete_file(file_id, self._access_token, is_family=False)
            self._logger.info(f"文件删除成功: {file_id}")
            
        except Exception as e:
            self._logger.error(f"删除文件失败: {e}")
            if "not found" in str(e).lower():
                raise FileNotFound(f"文件不存在: {file_id}")
            raise CloudStorageError(f"删除文件失败: {str(e)}")
    
    def move_file(self, file_id: str, new_parent_id: str, folder_id: str = None) -> CloudFile:
        """
        移动文件到新的父文件夹
        
        Args:
            file_id: 文件ID
            new_parent_id: 新父文件夹ID
            folder_id: 可选，源文件夹ID，用于获取文件信息
            
        Returns:
            CloudFile: 移动后的文件信息
            
        Raises:
            AuthException: 未登录
            FileNotFound: 文件不存在
            CloudStorageError: 移动失败
        """
        if not self.is_logged_in:
            raise AuthException("未登录")
        
        try:
            # 获取文件信息
            file_info = None
            if folder_id is not None:
                # 如果提供了源文件夹ID，先在该文件夹中查找文件
                try:
                    self._logger.info(f"在源文件夹 {folder_id} 中查找文件: {file_id}")
                    file_data = self._api.get_file_info_in_folder(file_id, folder_id, self._access_token, is_family=False)
                    if file_data:
                        file_info = CloudFile(
                            file_id=file_data.get('id', ''),
                            name=file_data.get('name', ''),
                            path=file_data.get('path', ''),
                            size=file_data.get('size', 0),
                            is_folder=file_data.get('isFolder', False),
                            parent_id=file_data.get('parentId'),
                            created_at=self._parse_timestamp(file_data.get('createDate')),
                            modified_at=self._parse_timestamp(file_data.get('lastOpTime')),
                            md5=file_data.get('md5')
                        )
                        self._logger.info(f"在源文件夹中找到文件: 名称={file_info.name}, 父文件夹ID={file_info.parent_id}")
                except Exception as e:
                    self._logger.warning(f"在源文件夹中查找文件失败: {e}")
            
            # 如果在源文件夹中未找到文件，尝试在根目录中查找
            if file_info is None:
                try:
                    self._logger.info(f"在根目录中查找文件: {file_id}")
                    root_folder_id = "-11"  # 天翼云盘根目录ID
                    file_data = self._api.get_file_info_in_folder(file_id, root_folder_id, self._access_token, is_family=False)
                    if file_data:
                        file_info = CloudFile(
                            file_id=file_data.get('id', ''),
                            name=file_data.get('name', ''),
                            path=file_data.get('path', ''),
                            size=file_data.get('size', 0),
                            is_folder=file_data.get('isFolder', False),
                            parent_id=file_data.get('parentId'),
                            created_at=self._parse_timestamp(file_data.get('createDate')),
                            modified_at=self._parse_timestamp(file_data.get('lastOpTime')),
                            md5=file_data.get('md5')
                        )
                        self._logger.info(f"在根目录中找到文件: 名称={file_info.name}, 父文件夹ID={file_info.parent_id}")
                except Exception as e:
                    self._logger.warning(f"在根目录中查找文件失败: {e}")
            
            # 如果仍然未找到文件，抛出异常
            if not file_info:
                raise FileNotFound(f"文件不存在: {file_id}")
            
            self._logger.info(f"开始移动文件: {file_info.name} 到目标文件夹: {new_parent_id}")
            
            # 调用API移动文件，修复参数传递问题
            # 与Go实现保持一致，只需要file_id和目标文件夹ID
            self._api.move_file(
                file_id, 
                new_parent_id,  # 目标文件夹ID
                self._access_token, 
                is_family=False,
                file_name=file_info.name,
                is_folder=file_info.is_folder
            )
            
            # 等待更长时间，确保文件移动完成
            self._logger.info("文件移动任务已提交，等待文件同步...")
            time.sleep(3)  # 增加等待时间
            
            # 获取移动后的文件信息，增加重试次数和等待时间
            max_retries = 1  # 增加重试次数
            for attempt in range(max_retries):
                try:
                    # 列出目标文件夹中的所有文件
                    files = self.list_files(new_parent_id)
                    
                    # 首先尝试通过原始文件ID查找
                    for file in files:
                        if file.file_id == file_id:
                            self._logger.info(f"成功在目标文件夹中找到文件(通过ID): {file.name}")
                            return file
                    
                    # 如果通过原始ID找不到，尝试通过文件名查找
                    for file in files:
                        if file.name == file_info.name:
                            self._logger.info(f"成功在目标文件夹中找到文件(通过名称): {file.name}")
                            return file
                    
                    # 如果没找到，等待更长时间后重试
                    if attempt < max_retries - 1:
                        wait_time = 2 * (attempt + 1)  # 递增等待时间
                        self._logger.info(f"未在目标文件夹中找到文件，等待 {wait_time} 秒后重试...")
                        time.sleep(wait_time)
                        continue
                    else:
                        raise CloudStorageError("移动后无法找到文件")
                        
                except Exception as retry_error:
                    if attempt < max_retries - 1:
                        wait_time = 2 * (attempt + 1)
                        self._logger.warning(f"查找移动后的文件时出错(尝试 {attempt + 1}/{max_retries}): {retry_error}")
                        time.sleep(wait_time)
                        continue
                    else:
                        raise retry_error
            
        except Exception as e:
            self._logger.error(f"移动文件失败: {e}")
            if "not found" in str(e).lower():
                raise FileNotFound(f"文件不存在: {file_id}")
            raise CloudStorageError(f"移动文件失败: {str(e)}")
    
    def rename_file(self, file_id: str, new_name: str) -> CloudFile:
        """
        重命名文件
        
        Args:
            file_id: 文件ID
            new_name: 新文件名
            
        Returns:
            CloudFile: 重命名后的文件信息
            
        Raises:
            AuthException: 未登录
            FileNotFound: 文件不存在
            CloudStorageError: 重命名失败
        """
        if not self.is_logged_in:
            raise AuthException("未登录")
        
        try:
            self._api.rename_file(file_id, new_name, self._access_token, is_family=False)
            
            # 获取重命名后的文件信息
            # 这里简化处理，实际应该从API返回中获取
            return CloudFile(
                file_id=file_id,
                name=new_name,
                path="",
                size=0,
                is_folder=False,
                parent_id=None
            )
            
        except Exception as e:
            self._logger.error(f"重命名文件失败: {e}")
            if "not found" in str(e).lower():
                raise FileNotFound(f"文件不存在: {file_id}")
            raise CloudStorageError(f"重命名文件失败: {str(e)}")
    
    def get_file_info(self, file_id: str, folder_id: str) -> CloudFile:
        """
        获取文件信息
        优化：支持在指定文件夹ID下查看文件信息，查询逻辑是扫描该文件夹下的文件列表，查找指定文件ID的文件
        
        Args:
            file_id: 文件ID
            folder_id: 文件夹ID，在该文件夹下查找文件
            
        Returns:
            CloudFile: 文件信息
            
        Raises:
            AuthException: 未登录
            FileNotFound: 文件不存在
            CloudStorageError: 获取失败
        """
        if not self.is_logged_in:
            raise AuthException("未登录")
        
        try:
            # 直接在指定文件夹中查找文件
            self._logger.info(f"在指定文件夹 {folder_id} 中查找文件: {file_id}")
            file_data = self._api.get_file_info_in_folder(file_id, folder_id, self._access_token, is_family=False)
            
            if file_data:
                self._logger.info(f"在文件夹 {folder_id} 中找到文件: {file_id}")
                return CloudFile(
                    file_id=file_data.get('id', ''),
                    name=file_data.get('name', ''),
                    path=file_data.get('path', ''),
                    size=file_data.get('size', 0),
                    is_folder=file_data.get('isFolder', False),
                    parent_id=file_data.get('parentId'),
                    created_at=self._parse_timestamp(file_data.get('createDate')),
                    modified_at=self._parse_timestamp(file_data.get('lastOpTime')),
                    md5=file_data.get('md5')
                )
            
            # 如果在指定文件夹中未找到文件，直接返回文件不存在
            raise FileNotFound(f"在文件夹 {folder_id} 中未找到文件: {file_id}")
            
        except FileNotFound:
            raise
        except Exception as e:
            self._logger.error(f"获取文件信息失败: {e}")
            if "not found" in str(e).lower():
                raise FileNotFound(f"文件不存在: {file_id}")
            raise CloudStorageError(f"获取文件信息失败: {str(e)}")
    
    def search_files(self, query: str) -> List[CloudFile]:
        """
        搜索文件
        
        Args:
            query: 搜索关键词
            
        Returns:
            List[CloudFile]: 搜索结果
            
        Raises:
            AuthException: 未登录
            CloudStorageError: 搜索失败
        """
        if not self.is_logged_in:
            raise AuthException("未登录")
        
        try:
            search_results = self._api.search_files(query, self._access_token, is_family=False)
            
            files = []
            for item in search_results:
                files.append(CloudFile(
                    file_id=item.get('id', ''),
                    name=item.get('name', ''),
                    path=item.get('path', ''),
                    size=item.get('size', 0),
                    is_folder=item.get('isFolder', False),
                    parent_id=item.get('parentId'),
                    created_at=self._parse_timestamp(item.get('createDate')),
                    modified_at=self._parse_timestamp(item.get('lastOpTime')),
                    md5=item.get('md5')
                ))
            
            return files
            
        except Exception as e:
            self._logger.error(f"搜索文件失败: {e}")
            raise CloudStorageError(f"搜索文件失败: {str(e)}")
    
    def list_trash(self) -> List[TrashItem]:
        """
        列出回收站中的文件 - 天翼TV暂不支持回收站功能
        
        Returns:
            List[TrashItem]: 回收站文件列表
            
        Raises:
            NotImplementedError: 天翼TV暂不支持回收站功能
        """
        raise NotImplementedError("天翼TV暂不支持回收站功能")
    
    def empty_trash(self) -> None:
        """
        清空回收站 - 天翼TV暂不支持回收站功能
        
        Raises:
            NotImplementedError: 天翼TV暂不支持回收站功能
        """
        raise NotImplementedError("天翼TV暂不支持回收站功能")
    
    def get_download_url(self, file_id: str) -> str:
        """
        获取文件下载链接
        
        Args:
            file_id: 文件ID
            
        Returns:
            str: 下载链接
            
        Raises:
            AuthException: 未登录
            FileNotFound: 文件不存在
            CloudStorageError: 获取失败
        """
        if not self.is_logged_in:
            raise AuthException("未登录")
        
        try:
            download_url = self._api.get_download_url(file_id, self._access_token, is_family=False)
            
            if not download_url:
                raise FileNotFound(f"文件不存在: {file_id}")
            
            return download_url
            
        except Exception as e:
            self._logger.error(f"获取下载链接失败: {e}")
            if "not found" in str(e).lower():
                raise FileNotFound(f"文件不存在: {file_id}")
            raise CloudStorageError(f"获取下载链接失败: {str(e)}")
    
    def check_fast_upload(self, file_name: str, file_data: bytes) -> bool:
        """
        检查是否支持快速上传（秒传）
        
        Args:
            file_name: 文件名
            file_data: 文件数据
            
        Returns:
            bool: 是否支持快速上传
        """
        try:
            if not file_data:
                return False
            
            # 计算文件MD5
            file_md5 = self._calculate_data_md5(file_data)
            if not file_md5:
                return False
            
            # 获取文件信息
            file_size = len(file_data)
            
            # 尝试创建上传会话，检查是否支持秒传
            upload_info = self._api.create_upload_file(
                parent_id="0",  # 根目录
                file_md5=file_md5,
                file_name=file_name,
                file_size=str(file_size),
                is_family=False  # 使用个人空间
            )
            
            # 检查FileDataExists字段，1表示文件已存在，支持秒传
            return upload_info.get('fileDataExists', 0) == 1
            
        except Exception as e:
            self._logger.warning(f"检查快速上传失败: {e}")
            return False
    
    def fast_upload_file(self, file_name: str, file_data: bytes, parent_id: Optional[str] = None) -> CloudFile:
        """
        快速上传文件（秒传）
        
        Args:
            file_name: 文件名
            file_data: 文件数据
            parent_id: 父文件夹ID，None表示根目录
            
        Returns:
            CloudFile: 上传后的文件信息
            
        Raises:
            CloudStorageError: 快速上传失败
        """
        try:
            if not file_data:
                raise CloudStorageError("文件数据为空")
            
            if not self._logged_in:
                raise AuthException("未登录，请先登录")
            
            # 计算文件MD5
            file_md5 = self._calculate_data_md5(file_data)
            if not file_md5:
                raise CloudStorageError("计算文件MD5失败")
            
            # 获取文件信息
            file_size = len(file_data)
            
            # 创建上传会话
            upload_info = self._api.create_upload_file(
                parent_id=parent_id or "0",
                file_md5=file_md5,
                file_name=file_name,
                file_size=str(file_size),
                is_family=False  # 使用个人空间
            )
            
            file_data_exists = upload_info.get('fileDataExists', 0)
            
            if file_data_exists != 1:
                raise CloudStorageError("文件不存在于云端，无法使用秒传")
            
            # 提交上传
            commit_result = self._api.commit_upload_file(
                commit_url=upload_info.get('fileCommitUrl', ''),
                upload_file_id=upload_info.get('uploadFileId', 0),
                is_family=False,  # 使用个人空间
                overwrite=True
            )
            
            # 解析返回的文件信息 - 支持JSON和XML格式
            file_data_result = None
            if 'file' in commit_result:
                # JSON格式
                file_data_result = commit_result['file']
            elif isinstance(commit_result, dict) and 'raw_response' in commit_result:
                # XML格式响应，需要解析
                raw_response = commit_result['raw_response']
                if raw_response.startswith('<?xml') or '<file>' in raw_response:
                    # 解析XML响应
                    try:
                        import xml.etree.ElementTree as ET
                        root = ET.fromstring(raw_response)
                        if root.tag == 'file':
                            file_data_result = {}
                            for child in root:
                                file_data_result[child.tag] = child.text
                    except Exception as xml_error:
                        self._logger.error(f"XML解析失败: {xml_error}")
                        raise CloudStorageError(f"提交上传响应解析失败: {xml_error}")
                else:
                    # 其他格式的原始响应
                    file_data_result = commit_result
            else:
                # 其他情况，直接使用响应
                file_data_result = commit_result
            
            if not file_data_result:
                raise CloudStorageError("无法解析提交上传的响应")
            
            # 创建并返回CloudFile对象
            return CloudFile(
                file_id=file_data_result.get('id', ''),
                name=file_data_result.get('name', file_name),
                path=f"/{file_name}",
                size=int(file_data_result.get('size', file_size)),
                is_folder=False,
                created_at=self._parse_timestamp(file_data_result.get('createDate')) if file_data_result.get('createDate') else None
            )
            
        except Exception as e:
            self._logger.error(f"快速上传文件失败: {e}")
            raise CloudStorageError(f"快速上传文件失败: {e}")
    
    def _calculate_data_md5(self, data: bytes) -> Optional[str]:
        """计算数据MD5哈希值"""
        try:
            import hashlib
            hash_md5 = hashlib.md5()
            hash_md5.update(data)
            return hash_md5.hexdigest()
        except Exception as e:
            self._logger.error(f"计算数据MD5失败: {e}")
            return None
    
    def _calculate_file_md5(self, file_path: str) -> Optional[str]:
        """计算文件MD5哈希值"""
        try:
            import hashlib
            
            hash_md5 = hashlib.md5()
            with open(file_path, "rb") as f:
                for chunk in iter(lambda: f.read(4096), b""):
                    hash_md5.update(chunk)
            return hash_md5.hexdigest()
        except Exception as e:
            self._logger.error(f"计算文件MD5失败: {e}")
            return None
    
    def _validate_token(self) -> bool:
        """验证当前token是否有效"""
        try:
            # 尝试获取用户信息来验证token
            self._api.get_user_info(self._access_token)
            return True
        except Exception:
            return False
    
    def _create_persistent_info(self, login_data: Dict[str, Any]) -> PersistentLoginInfo:
        """创建持久化登录信息"""
        return PersistentLoginInfo(
            provider="tianyi_tv",
            user_id=login_data.get('loginName', ''),
            access_token=login_data.get('accessToken', ''),
            refresh_token=login_data.get('refreshToken', ''),
            expires_at=self._parse_timestamp(login_data.get('expiresAt'))
        )
    
    def _parse_timestamp(self, timestamp) -> Optional[datetime]:
        """解析时间戳"""
        if not timestamp:
            return None
        
        try:
            if isinstance(timestamp, str):
                # 尝试解析ISO格式
                if 'T' in timestamp:
                    return datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
                # 尝试解析数字字符串
                timestamp = float(timestamp)
            
            if isinstance(timestamp, (int, float)):
                # 处理毫秒时间戳
                if timestamp > 1e10:
                    timestamp = timestamp / 1000
                return datetime.fromtimestamp(timestamp)
            
            return None
        except (ValueError, OSError):
            return None